import java.util.HashMap;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
public class GrammarParse{
	//预测表
	static HashMap<String, Formula> predictMap;
	//词法分析的结果作为输入串
	static ArrayList<String> input_str;
	//*语法分析的符号栈，在语法分析中的重要数据结构
	static ArrayList<String> symbol_stack;
	//语法分析的输出
	static ArrayList<String> grammar_parse_result;
	//语法分析输出结果的计数器
	static int grammarParseResultCounter;
	
	public GrammarParse() {
		predictMap = new HashMap<>();
		input_str = new ArrayList<>();
		symbol_stack = new ArrayList<>();
		grammar_parse_result = new ArrayList<>();
		grammarParseResultCounter = 0;
	}
	
	public GrammarParse(HashMap<String, Formula> predictMap,ArrayList<String> input_str) {
		//初始化，装配预测表和词法分析得到的结果字符串
		GrammarParse.predictMap = predictMap;
		GrammarParse.input_str = input_str;
		symbol_stack = new ArrayList<>();
		grammar_parse_result = new ArrayList<>();
		grammarParseResultCounter = 0;
	}
	
	//在控制台输出
	static void outputInConsole() {
		System.out.println("开始输出语法分析结果至控制台: ————————————————————————");
		for (String result : grammar_parse_result) {
			
			System.out.println(result);
		}
	}
	
	 //输出语法分析结果
    static void printParseResult() {
        System.out.println("开始输出语法分析结果: ————————————————————————");
        for (String result : grammar_parse_result) {
            System.out.println(result);
        }
        try {
            BufferedWriter out = new BufferedWriter(new FileWriter(Config.parseResultPath));
            for (String s : grammar_parse_result) {
                out.write(s + "\n");
            }
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
	//语法分析
	static void Parse() {
        // ------
        // 将 # 压入栈
        symbol_stack.add("#");
        input_str.add("#"); //输入串在最后也需要放 #
        // ------

        // 初始符号压入栈
//        symbol_stack.add("S");
        symbol_stack.add(Config.initSymbol);

        String predictMapKey;   // PredictMap-Key
//        String process="";


        // 符号栈和输入串如果同时为0，那么语法分析结束
//        while (symbol_stack.size()>0 && input_str.size()>0 ) {
        while (true) {
            grammarParseResultCounter++; // 语法分析结果的计数器加一
            if (symbol_stack.get(symbol_stack.size()-1).equals("#") && input_str.get(0).equals("#")) {
                grammar_parse_result.add(grammarParseResultCounter + "\t"
                        + "EOF" + "#"
                        + "EOF" + "\t" + "accept");
                break;
            }
            // 输入缓冲区与推导符号串第一个字符相等的话，删掉
            try {
                if(input_str.get(0).equals(symbol_stack.get(symbol_stack.size()-1))){
                    // 语法分析的结果写入栈中
                    grammar_parse_result.add(grammarParseResultCounter + "\t"
                            + symbol_stack.get(symbol_stack.size()-1) + "#"
                            + input_str.get(0) + "\t" + "move");
                    input_str.remove(0);    // 输入字符移除第一个，类似于指针向后遍历
                    symbol_stack.remove(symbol_stack.size()-1); // 符号栈移除栈顶
                    continue;
                }
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }

            // 匹配字符
            predictMapKey = PredictMap.getMapKey(input_str.get(0), symbol_stack.get(symbol_stack.size()-1));

            // 能够找到匹配的
            Formula formula = predictMap.get(predictMapKey);    // 找到文法
            if (formula != null) {  // 文法不为空，为空报错
                // 语法分析的结果写入栈中
                grammar_parse_result.add(grammarParseResultCounter + "\t"
                        + symbol_stack.get(symbol_stack.size()-1) + "#"
                        + input_str.get(0) + "\t" + "reduction");
                // 符号栈的最后一个元素如果是 #, 就不能删除了
                if (symbol_stack.get(symbol_stack.size()-1).equals("#")) {
                } else {
                    symbol_stack.remove(symbol_stack.size()-1); // 删除符号栈中最后一个元素
                }
                String[] rights = formula.getRight();   // 文法的右侧
                if (rights[0].equals("$")) {    // E->$，不能压入空
                    continue;
                }
                for (int i = rights.length-1; i >= 0; i--) {
                    // 将文法右侧的非终结符反向压入栈中
                    symbol_stack.add(rights[i]);
                }
            }

            else {
                // 语法分析的结果写入栈中
                grammar_parse_result.add(grammarParseResultCounter + "\t"
                        + symbol_stack.get(symbol_stack.size()-1) + "#"
                        + input_str.get(0) + "\t" + "error");
                return; // 遇到error直接返回
            }
        }
    }
}